package cn.com.cetccst.mdm.engine;

import static android.os.Build.VERSION.SDK_INT;

import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.UserManager;
import android.text.TextUtils;
import android.util.Log;

import androidx.core.content.FileProvider;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/*
 *wifi、micphone、修改时区不行
 *
 *
 *
 *
 * */

public class DeviceOwnerMdmEngine extends BaseMDMEngine {

    private static final String TAG = "DeviceOwnerMdmEngine";

    protected ActivityManager activityManager;
    protected DevicePolicyManager dpm;
    protected UserManager userManager;
    protected NotificationManager notificationManager;
    protected PackageManager packageManager;

    public DeviceOwnerMdmEngine(Context context) {
        super(context);
        dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
        activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
        notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        packageManager = context.getPackageManager();
    }


    @Override
    public void controlBluetooth(boolean disabled) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // Device Owner can use DISALLOW_BLUETOOTH to disable bluetooth completely from Android 8+
            Log.e(TAG, "disableBluetooth: 1");
            perform(UserManager.DISALLOW_BLUETOOTH, disabled);
        } else {
            perform(UserManager.DISALLOW_CONFIG_BLUETOOTH, disabled);
            Log.e(TAG, "disableBluetooth: 2");
        }
    }

    @Override
    public boolean isBluetoothControlled() {
        final BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
        if (bluetoothManager != null) {
            BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
            if (bluetoothAdapter != null) {
                return bluetoothAdapter.isEnabled();
            }
        }
        return false;
    }

    @Override
    public void controlCamera(boolean disabled) {
        if (disabled) {
            if (!dpm.getCameraDisabled(adminComponent)) {
                dpm.setCameraDisabled(adminComponent, true);
                Log.e(TAG, "set camera to disable via device admin.");
            }
        } else {
            if (dpm.getCameraDisabled(adminComponent)) {
                dpm.setCameraDisabled(adminComponent, false);
                Log.e(TAG, "set camera to enable via device admin.");
            }
        }
    }

    @Override
    public boolean isCameraControlled() {
        return dpm.getCameraDisabled(adminComponent);
    }

    @Override
    public void controlWifi(boolean disabled) {
        Log.e(TAG, "disableWifi: " + disabled);
        turnOffWifi(disabled);
        perform(UserManager.DISALLOW_CONFIG_WIFI, disabled);
    }

    protected void turnOffWifi(boolean disable) {
        if (disable) {
            // turn off wifi setting soft
            WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
            if (wifiManager != null && wifiManager.isWifiEnabled()) {
                Log.e(TAG, "setWifiEnabled:false ");
                wifiManager.setWifiEnabled(false);
            }
        } else {
        }
    }

    @Override
    public boolean isWifiControlled() {
        WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        if (wifiManager != null) {
            return !wifiManager.isWifiEnabled();
        }
        return false;
    }

    @Override
    public void controlMicroPhone(boolean disabled) {
        perform(UserManager.DISALLOW_UNMUTE_MICROPHONE, disabled);
    }

    @Override
    public boolean isMicroPhoneControlled() {
        return false;
    }


    @Override
    public void controlExternalStorage(boolean disabled) {
        perform(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, disabled);
    }

    @Override
    public boolean isExternalStorageControlled() {
        return false;
    }


    @Override
    public void controlScreenShot(boolean disabled) {
        if (disabled) {
            if (!dpm.getScreenCaptureDisabled(adminComponent)) {
                dpm.setScreenCaptureDisabled(adminComponent, true);
                Log.e(TAG, "restrict screen capture via Owner API");
            }
        } else {
            if (dpm.getScreenCaptureDisabled(adminComponent)) {
                dpm.setScreenCaptureDisabled(adminComponent, false);
                Log.e(TAG, "release screen capture via Owner API");
            }
        }
    }

    @Override
    public boolean isScreenShotControlled() {
        return false;
    }


    @Override
    public void controlNFC(boolean disabled) {
        perform(UserManager.DISALLOW_OUTGOING_BEAM, disabled);
    }

    @Override
    public boolean isNFCControlled() {
        return false;
    }


    @Override
    public void controlMobileHotSpot(boolean disabled) {
        perform(UserManager.DISALLOW_CONFIG_TETHERING, disabled);
    }

    @Override
    public boolean isMobileHotSpotControlled() {
        return false;
    }


    @Override
    public void controlCallout(boolean disabled) {
        perform(UserManager.DISALLOW_OUTGOING_CALLS, disabled);
    }

    @Override
    public boolean isCalloutControlled() {
        return false;
    }


    @Override
    public void controlSms(boolean disabled) {
        perform(UserManager.DISALLOW_SMS, disabled);
    }

    @Override
    public boolean isSmsControlled() {
        return false;
    }


    @Override
    public void controlMobileData(boolean disabled) {
        perform(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, disabled);
    }

    @Override
    public boolean isMobileDataControlled() {
        return false;
    }


    @Override
    public void controlVolumeDown(boolean disabled) {
        perform(UserManager.DISALLOW_ADJUST_VOLUME, disabled);
    }

    @Override
    public boolean isVolumeDownControlled() {
        return false;
    }


    @Override
    public void controlAutoTime(boolean disabled) {
        if (disabled) {
            if (!dpm.getAutoTimeRequired()) {
                dpm.setAutoTimeRequired(adminComponent, true);
                Log.e(TAG, "restrict time via Owner API");
            }
        } else {
            if (dpm.getAutoTimeRequired()) {
                dpm.setAutoTimeRequired(adminComponent, false);
                Log.e(TAG, "release time via Owner API");
            }
        }
    }

    @Override
    public boolean isAutoTimeControlled() {
        return false;
    }


    @Override
    public void controlUsbData(boolean disabled) {
        perform(UserManager.DISALLOW_USB_FILE_TRANSFER, disabled);
    }

    @Override
    public boolean isUsbDataControlled() {
        return false;
    }


    @Override
    public void controlUsbDebug(boolean disabled) {
        perform(UserManager.DISALLOW_DEBUGGING_FEATURES, disabled);

    }

    @Override
    public boolean isUsbDebugControlled() {
        return false;
    }


    @Override
    public void controlRestoreFactory(boolean disabled) {
        perform(UserManager.DISALLOW_FACTORY_RESET, disabled);
    }

    @Override
    public boolean isRestoreFactoryControlled() {
        return false;
    }

    @Override
    public void controlGPS(boolean disabled) {
        perform(UserManager.DISALLOW_SHARE_LOCATION, disabled);
    }

    @Override
    public boolean setDisallowRunningApps(List<String> packageNames, boolean isBlock) {
        List<String> pendingPackages = new ArrayList<>();
        if (packageNames != null) {
            for (String source : packageNames) {
                PackageInfo packageInfo = null;
                try {
                    packageInfo = packageManager.getPackageInfo(source, PackageManager.GET_UNINSTALLED_PACKAGES);
                } catch (PackageManager.NameNotFoundException e) {
                    //
                }
                if (packageInfo == null) {
                    continue;
                }
                if (isBlock) {
                    if (!isPackageSuspend(source, 0)) {
                        pendingPackages.add(source);
                    }
                } else {
                    if (isPackageSuspend(source, 0)) {
                        pendingPackages.add(source);
                    }
                }
            }
        }
        if (!pendingPackages.isEmpty()) {
            setPackagesSuspend(pendingPackages.toArray(new String[0]), isBlock, 0);
            Log.e(TAG, "setPackagesSuspend done with size " + pendingPackages.size() + " on user " + 0);
        }
        return true;
    }

    @Override
    public void installPackage(String apkPath) {
        Uri uri;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            uri = FileProvider.getUriForFile(context, fileProviderAuthority, new File(apkPath));
        } else {
            uri = Uri.fromFile(new File(apkPath));
        }
        if (isProfileOwner()) {
            Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE, uri);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
            intent.setDataAndType(uri, "application/vnd.android.package-archive");
            context.startActivity(intent);
            Log.e(TAG, "profile owner calls Android N system installer for " + uri);
        } else {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                PackageInfo packageInfo = context.getPackageManager().getPackageArchiveInfo(apkPath, 0);
                Log.e(TAG, "Silent install is going to happen on AOSP API: " + uri);
                try {
                    ParcelFileDescriptor parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uri, "r");
                    if (parcelFileDescriptor == null) {
                        return;
                    }
                    FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
                    InputStream in;
                    OutputStream out;
                    in = new FileInputStream(fileDescriptor);

                    PackageInstaller pi = packageManager.getPackageInstaller();
                    pi.registerSessionCallback(new PackageInstaller.SessionCallback() {
                        @Override
                        public void onCreated(int sessionId) {
                            Log.e(TAG, "Install Start sessionId-> " + sessionId);
                        }

                        @Override
                        public void onBadgingChanged(int sessionId) {
                        }

                        @Override
                        public void onActiveChanged(int sessionId, boolean active) {
                        }

                        @Override
                        public void onProgressChanged(int sessionId, float progress) {
                        }

                        @Override
                        public void onFinished(int sessionId, boolean success) {

                            if (success) {
                                Log.e(TAG, "Silent Install Success");
                            } else {
                                Log.e(TAG, "Silent Install Fail");
                            }


                        }
                    }, new Handler(Looper.getMainLooper()) {
                        @Override
                        public void handleMessage(Message msg) {
                            super.handleMessage(msg);
                            // install command is done
                            if (msg.what == -1) {
//                            InstallingAppManage.remove(packageName);
                                if (msg.arg1 != 1) {
                                    Log.e(TAG, "install app  failed");
                                }
                            }
                        }
                    });

                    int sessId = pi.createSession(new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL));
                    PackageInstaller.Session session = pi.openSession(sessId);
                    // write updated APK file to out
                    long sizeBytes = 0;
                    out = session.openWrite("my_app_session", 0, sizeBytes);
                    byte[] buffer = new byte[65536];
                    int c;
                    while ((c = in.read(buffer)) != -1) {
                        out.write(buffer, 0, c);
                    }
                    session.fsync(out);
                    in.close();
                    out.close();
                    Intent intent = new Intent();
                    PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
                            1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
                    session.commit(pendingIntent.getIntentSender());
                    session.close();
                    Log.e(TAG, "Silent install done with AOSP API.");
                } catch (Throwable e) {
                    Log.e(TAG, "Silent install failed with AOSP API", e);
                }
            }
        }
    }

    public boolean isProfileOwner() {
        try {
            return dpm != null && (SDK_INT >= Build.VERSION_CODES.N ?
                    dpm.isManagedProfile(adminComponent) : dpm.isProfileOwnerApp(context.getPackageName()));

        } catch (SecurityException ex) {
            //ex.printStackTrace();
        }
        return false;
    }

    @Override
    public void uninstallPackage(String packageName) {
        if (TextUtils.isEmpty(packageName)) {
            return;
        }
        if (this.isDeviceOwnerControlled()) {
            Intent intent = new Intent();
            PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 2, intent, PendingIntent.FLAG_UPDATE_CURRENT);
            PackageInstaller mPackageInstaller = context.getPackageManager().getPackageInstaller();
            mPackageInstaller.uninstall(packageName, pendingIntent.getIntentSender());
            Log.e(TAG, "Silent uninstall done with Device Owner API.");
        } else {
        }
    }

    public boolean isDeviceOwnerControlled() {
        return dpm != null && dpm.isDeviceOwnerApp(context.getPackageName());
    }


    @Override
    public void factoryReset() {
        if (dpm.isAdminActive(adminComponent)) {
            dpm.wipeData(DevicePolicyManager.WIPE_EXTERNAL_STORAGE);
            Log.w(TAG, "current space has been wiped completely.");
        }
    }


    protected String[] setPackagesSuspend(String[] packageNames, boolean suspend, int userId) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return dpm.setPackagesSuspended(adminComponent, packageNames, suspend);
        }
        try {
            @SuppressLint("PrivateApi")
            Method method = packageManager.getClass().getDeclaredMethod("setPackagesSuspendedAsUser",
                    String[].class, boolean.class, int.class);
            return (String[]) method.invoke(packageManager, packageNames, suspend, userId);
        } catch (NoSuchMethodException e) {
            Log.e(TAG, "no API setPackagesSuspend on this ROM.");
            return null;
        } catch (Exception e) {
            Log.e(TAG, "call setPackageSuspend failed packageNames:", e);
            return null;
        }
    }

    protected boolean isPackageSuspend(String packageName, int userId) {
        try {
            @SuppressLint("PrivateApi")
            Method method = packageManager.getClass().getDeclaredMethod("isPackageSuspendedForUser", String.class, int.class);
            return (Boolean) method.invoke(packageManager, packageName, userId);
        } catch (NoSuchMethodException e) {
            Log.e(TAG, "no API isPackageSuspend on this ROM.");
            return false;
        } catch (Exception e) {
            Log.e(TAG, "call isPackageSuspend failed packageName:" + packageName, e);
            return false;
        }
    }

    @Override
    public boolean setDevicePassword(String password) {
        boolean succeed = false;
        try {
            if (dpm.isAdminActive(adminComponent)) {
                if (SDK_INT >= Build.VERSION_CODES.N) {
                    succeed = dpm.resetPassword(password, 0);
                    Log.e(TAG, "try to reset device password on Android N+ " + succeed);
                } else {
                    succeed = dpm.resetPassword(password, 0);
                    Log.e(TAG, "reset device password done with flag " + 0);
                }
            }
        } catch (Exception e) {
            Log.e(TAG, "can reset device password", e);
        }

        return succeed;
    }

    public boolean perform(String key, boolean disable) {
        if (disable) {
            if (!userManager.hasUserRestriction(key)) {
                dpm.addUserRestriction(adminComponent, key);
                Log.e(TAG, key + " user restriction has been added via Owner Engine");
                return true;
            }
        } else {
            if (userManager.hasUserRestriction(key)) {
                dpm.clearUserRestriction(adminComponent, key);
                Log.e(TAG, key + " user restriction has been removed via Owner Engine");
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean setPermittedAccessibility(List<String> packageNames) {
        boolean res = dpm.setPermittedAccessibilityServices(adminComponent, packageNames);
        Log.e(TAG, "setPermittedAccessibility: " + res);
        getPermittedAccessibilityServices();
        return res;
    }

    @Override
    public List<String> getPermittedAccessibilityServices() {
        List<String> apps = dpm.getPermittedAccessibilityServices(adminComponent);
        Log.e(TAG, "getPermittedAccessibility apps size: " + apps.size());
        return apps;
    }


    //以下为没有提供接口的功能

    @Override
    public void formatSDCard() {

    }

    @Override
    public boolean setInstallSourceApps(List<String> packageNames) {
        return false;
    }

    @Override
    public List<String> getInstallSourceApps() {
        return null;
    }

    @Override
    public boolean setNetworkWhiteListApps(List<String> packageNames) {
        return false;
    }

    @Override
    public List<String> getNetworkWhiteListApps() {
        return null;
    }

    @Override
    public boolean setKeepLiveApps(List<String> packageNames) {
        return false;
    }

    @Override
    public List<String> getKeepLiveApps() {
        return null;
    }

    @Override
    public boolean setSuperApps(List<String> packageNames) {
        return false;
    }

    @Override
    public List<String> getSuperApps() {
        return null;
    }

    @Override
    public void controlSystemUpgrade(boolean disabled) {

    }

    @Override
    public boolean isSystemUpgradeControlled() {
        return false;
    }

    @Override
    public List<String> getDisallowRunningApps() {
        return null;
    }

    @Override
    public String getName() {
        return "DO";
    }
}
